﻿using UnityEngine;
using System.Collections.Generic;
using ProtoBuf.Message;
namespace Room
{
    public class ViewController
    {
        private const float MIN_CHECK_SQR_DISTANCE = 1;
        private const float MIN_CHECK_SQR_DISTANCE_MAP = 2;
        private Vector3 lastDetectPosition;
        private Transform player;
        public RoomCharactorManager roomCharactorManager;
        private float outRadius = 225f;
        private float delayInfoTime = 30f;
        private bool running = true;
        private float lastDetectTime = 0;

        private List<MeshRenderer> listMeshRender = new List<MeshRenderer>();
        public bool detectMap = false;

        public ViewController(RoomCharactorManager roomCharactorManager)
        {
            this.roomCharactorManager = roomCharactorManager;
        }

        public void SetPlayer(Transform player)
        {
            this.player = player;
        }
        public void Tick()
        {
            if (player == null || roomCharactorManager == null)
            {
                return;
            }
            //更新前提限制后期需要改动
            Vector3 dis = player.localPosition - lastDetectPosition;
            dis.y = 0;
            if (dis.sqrMagnitude >= MIN_CHECK_SQR_DISTANCE || Time.unscaledTime - lastDetectTime >= 1)
            {
                lastDetectPosition = player.localPosition;
                DetectView();
            }
            if (dis.sqrMagnitude >= MIN_CHECK_SQR_DISTANCE)
            {
                if (detectMap)
                {
                    DetectMap();
                }
            }
        }

        public void Pause()
        {
            running = false;
            listMeshRender.Clear();
        }

        public void Resume()
        {
            running = true;
            //lastDetectTime = Time.unscaledTime;
            listMeshRender.Clear();
        }

        public void DetectMap()
        {

            if (listMeshRender.Count == 0)
            {
                var map = GameObject.Find(UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
                if (map == null)
                {
                    return;
                }
                TravelMesh(map.transform);
            }
            for (int i = 0; i < listMeshRender.Count; i++)
            {
                var meshRender = listMeshRender[i];
                var bounds = meshRender.bounds;

                if (bounds.min.x > player.position.x + 10f || bounds.max.x < player.position.x - 10f
                    || bounds.min.z > player.position.z + 15f || bounds.max.z < player.position.z - 7f)
                {
                    if (meshRender.gameObject.activeSelf)
                        meshRender.gameObject.SetActive(false);
                }
                else
                {
                    if (!meshRender.gameObject.activeSelf)
                        meshRender.gameObject.SetActive(true);
                }
            }
            //Debug.Log("[DetectMap]obj num:" + listMeshRender.Count);
        }

        private void TravelMesh(Transform t)
        {
            var meshRender = t.GetComponent<MeshRenderer>();
            if (meshRender != null)
            {
                listMeshRender.Add(meshRender);
            }
            for (int i = 0; i < t.childCount; i++)
            {
                TravelMesh(t.GetChild(i));
            }
        }

        public void DetectView()
        {
            if (running)
            {
                lastDetectTime = Time.unscaledTime;
                List<RoomCharactor> charactors = new List<RoomCharactor>();
                //List<RoomCharactor> charactors = new List<RoomCharactor>();

                List<RoomCharactor> destroyCharactors = new List<RoomCharactor>();
                CSMovePlayerInfo csMpi = new CSMovePlayerInfo();
                var chs = roomCharactorManager.GetCharactors();
                //Debug.Log("<color=yellow>"+chs.Count + "</color>");
                foreach (var kvp in chs)
                {

                    if (CheckCharactorDeath(kvp.Value))
                    {
                        kvp.Value.SetInView(false);
                        continue;
                    }

                    Vector3 p = kvp.Value.transform.localPosition - player.localPosition;
                    if (p.x * p.x >= outRadius && p.z * p.z >= outRadius)
                    {
                        if (kvp.Value.type == CharactorType.OtherPlayer 
                            || kvp.Value.type == CharactorType.UnionFightOther)
                            destroyCharactors.Add(kvp.Value);
                    }
                    else
                    {
                        //Vector3 screenPos = Camera.main.WorldToScreenPoint(kvp.Value.transform.position);
                        //if (screenPos.x > 0 && screenPos.x < Screen.width && screenPos.y > 0 && screenPos.y < Screen.height)
                        //{
                        if (p.x * p.x < 100f && p.z < 10f && p.z > -5f)
                        {
                            //视野内
                            //kvp.Value.SetInView(true);
                            if (Time.unscaledTime - kvp.Value.lastUpdateTime > delayInfoTime 
                                && (kvp.Value.type == CharactorType.OtherPlayer || kvp.Value.type == CharactorType.UnionFightOther))
                            {
                                kvp.Value.lastUpdateTime = Time.unscaledTime;
                                csMpi.playerIds.Add(long.Parse(kvp.Key));
                            }
                            if (   kvp.Value.type == CharactorType.OtherPlayer
                                || kvp.Value.type == CharactorType.SelfPlayer
                                || kvp.Value.type == CharactorType.UnionFightSelf
                                || kvp.Value.type == CharactorType.UnionFightOther)
                            {
                                AddAndSortByLastActiveTime(charactors, kvp.Value);
                            }
                            else
                            {
                                kvp.Value.SetInView(true);
                            }
                        }
                        else
                        {
                            kvp.Value.SetInView(false);
                            //if (kvp.Value.type == CharactorType.OtherPlayer)
                            //    kvp.Value.SetLodLevel(0);
                        }
                    }

                }
                if (csMpi.playerIds.Count > 0)
                {
                    NetAPI.SendSocket(OpDefine.CSMovePlayerInfo, csMpi);
                }
                int maxPlayerNum = Mathf.Min(StaticData.maxPlayerInView, RenderManager.MaxPlayerNum);
                int showCount = 0;
                List<RoomCharactor> newCharactors = new List<RoomCharactor>();
                List<RoomCharactor> showCharactors = new List<RoomCharactor>(charactors.Count); //保存自己以及可视区的其他玩家
                for (int i = 0; i < charactors.Count; i++)
                {
                    var ch = charactors[i];
                    if (AddAndSortByZ(showCharactors, ch))
                    {
                        if (showCount <= maxPlayerNum)
                        {
                            if (ch.GetInView())
                            {
                                showCount++;
                            }
                            else
                            {
                                newCharactors.Add(ch);
                            }
                        }
                        else
                        {
                            ch.SetInView(false);
                        }
                    }
                    else
                    {
                        ch.SetInView(false);
                    }
                }
                for (int i = 0; i < newCharactors.Count; i++)
                {
                    if (showCount < maxPlayerNum)
                    {
                        showCount++;
                        newCharactors[i].SetInView(true);
                    }
                }

                for (int i = 0; i < destroyCharactors.Count; i++)
                {
                    roomCharactorManager.DestroyCharactor(destroyCharactors[i].name);
                }

            }
        }

        private void AddAndSortByLastActiveTime(List<RoomCharactor> showCharactors, RoomCharactor rc)
        {
            int first = 0;
            int last = showCharactors.Count - 1;
            int middle = (first + last) / 2;
            if (last == -1)
            {
                showCharactors.Add(rc);
                return;
            }
            float time = rc.LastActiveTime;
            //空列表
            while (last >= first)
            {
                float mt = showCharactors[middle].LastActiveTime;
                if (time == mt)
                {
                    showCharactors.Insert(middle, rc);
                    return;
                }
                else if (time < mt)
                {
                    first = middle + 1;
                }
                else
                {
                    last = middle - 1;
                }
                middle = (first + last) / 2;
            }
            showCharactors.Insert(first, rc);
        }

        private float ZD = 0.3f;
        private float YD = 0.2f;
        private float XD = 0.2f;
        private bool AddAndSortByZ(List<RoomCharactor> showCharactors, RoomCharactor rc)
        {
            int first = 0;
            int last = showCharactors.Count - 1;
            int middle = (first + last) / 2;
            float z = rc.transform.localPosition.z;
            if (last == -1)
            {
                showCharactors.Add(rc);
            }
            else
            {
                //空列表
                while (last >= first)
                {
                    if (z > showCharactors[middle].transform.localPosition.z)
                    {
                        first = middle + 1;
                    }
                    else
                    {
                        last = middle - 1;
                    }
                    middle = (first + last) / 2;
                }
                showCharactors.Insert(first, rc);
            }

            if (rc.type == CharactorType.SelfPlayer || rc.type == CharactorType.UnionFightSelf)
            {//自己必然不做隐身处理
                //rc.SetLodLevel(4);
                return true;
            }

            Vector3 rcPos = rc.transform.localPosition;
            int count = 0;
            for (int i = (first - 1); i >= 0; i--)
            {
                RoomCharactor obj = showCharactors[i];
                Vector3 objPos = obj.transform.localPosition;
                if ((z - objPos.z) >= ZD)
                {//过滤ZD外的人物
                    break;
                }
                if ((rcPos.y - objPos.y) > YD)
                {//过滤相差YD以上的人物
                    continue;
                }
                float xd = rcPos.x - objPos.x;
                if (obj.isUiInView
                    && xd < XD && xd > -XD)
                {//取XD差距内的人物
                    if (++count > 1)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        private bool CheckCharactorDeath(RoomCharactor ch)
        {
            if (ch.type == CharactorType.ServerMonster)
            {
                var ai = ch.ai as RCAIServerMonster;
                if (ai != null && ai.curState == ServerMonsterAIState.Death)
                {
                    return true;
                }
            }
            else if (ch.type == CharactorType.OtherPlayer ||
                ch.type == CharactorType.SelfPlayer)
            {
                var ai = ch.ai as RCAIActor;
                if (ai != null && ai.curState == PlayerAIState.Death)
                {
                    return true;
                }
            }
            else if (ch.type == CharactorType.UnionFightSelf ||
                ch.type == CharactorType.UnionFightOther)
            {
                var ai = ch.ai as RCAIUnionActor;
                if (ai != null && ai.CurrState == UnionActorState.Death)
                {
                    return true;
                }
            }
            else if (ch.type == CharactorType.UnionFightGuard)
            {
                var ai = ch.ai as RCAIGuard;
                if (ai != null && ai.CurrState == UnionGuardState.Death)
                {
                    return true;
                }
            }
            else if (ch.type == CharactorType.UnionFightMonster)
            {
                var ai = ch.ai as RCAIUnionMonster;
                if (ai != null && ai.CurrState == UnionMonsterState.Death)
                {
                    return true;
                }
            }
            return false;
        }

    }
}